﻿#region Copyright (c) 2007-2010 Mikko Salmi, Contributors
/*
 *
 * Copyright (c) 2007-2010 Mikko Salmi, Contributors
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 * and associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 * 
*/
#endregion // Copyright

using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Xml.Serialization;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Navigation;
using Microsoft.SharePoint.WebPartPages;

namespace CodePlex.WebParts
{
    [XmlRoot(Namespace = "CodePlex.WebParts")]
    [Guid("9EDA5429-8AD0-42E0-9B10-C7C5449B15EF")]
    public class BingMapsWebPart : AdvancedWebPart
    {
        private const string listNameDefault = "Map Information";
        string listName = listNameDefault;

        [Personalizable(PersonalizationScope.Shared),
        WebBrowsable,
        WebDisplayName("List Name"),
        WebDescription("The name of the list containing Bing Maps information."),
        SPWebCategoryName("Bing Maps")]
        public string ListName
        {
            get
            {
                return listName;
            }
            set
            {
                listName = value;
            }
        }

        private const int zoomLevelDefault = 12;
        int zoomLevel = zoomLevelDefault;

        [Personalizable(PersonalizationScope.Shared),
        WebBrowsable,
        WebDisplayName("Zoom Level"),
        WebDescription("Initial Zoom Level"),
        SPWebCategoryName("Bing Maps")]
        public int ZoomLevel
        {
            get
            {
                return zoomLevel;
            }
            set
            {
                zoomLevel = value;
            }
        }

        private const double latitudeDefault = 0;
        double latitude = latitudeDefault;

        [Personalizable(PersonalizationScope.Shared),
        WebBrowsable,
        WebDisplayName("Latitude"),
        WebDescription("Map Center Latitude"),
        SPWebCategoryName("Bing Maps")]
        public double Latitude
        {
            get
            {
                return latitude;
            }
            set
            {
                latitude = value;
            }
        }

        private const double longitudeDefault = 0;
        double longitude = longitudeDefault;

        [Personalizable(PersonalizationScope.Shared),
        WebBrowsable,
        WebDisplayName("Longitude"),
        WebDescription("Map Center Longitude"),
        SPWebCategoryName("Bing Maps")]
        public double Longitude
        {
            get
            {
                return longitude;
            }
            set
            {
                longitude = value;
            }
        }

        private const bool aerialModeDefault = true;
        bool aerialMode = aerialModeDefault;

        [Personalizable(PersonalizationScope.Shared),
        WebBrowsable,
        WebDisplayName("Aerial Mode"),
        WebDescription("Display aerial mode or road mode"),
        SPWebCategoryName("Bing Maps")]
        public bool AerialMode
        {
            get
            {
                return aerialMode;
            }
            set
            {
                aerialMode = value;
            }
        }

        private const bool labelsDefault = true;
        bool labels = labelsDefault;

        [Personalizable(PersonalizationScope.Shared),
        WebBrowsable,
        WebDisplayName("Aerial Mode Labels"),
        WebDescription("Display labels in aerial mode"),
        SPWebCategoryName("Bing Maps")]
        public bool Labels
        {
            get
            {
                return labels;
            }
            set
            {
                labels = value;
            }
        }

        private const int mapWidthDefault = 800;
        int mapWidth = mapWidthDefault;

        [Personalizable(PersonalizationScope.Shared),
        WebBrowsable,
        WebDisplayName("Map Width"),
        WebDescription("Map Width"),
        SPWebCategoryName("Bing Maps")]
        public int MapWidth
        {
            get
            {
                return mapWidth;
            }
            set
            {
                mapWidth = value;
            }
        }

        private const int mapHeightDefault = 600;
        int mapHeight = mapHeightDefault;

        [Personalizable(PersonalizationScope.Shared),
        WebBrowsable,
        WebDisplayName("Map Height"),
        WebDescription("Map Height"),
        SPWebCategoryName("Bing Maps")]
        public int MapHeight
        {
            get
            {
                return mapHeight;
            }
            set
            {
                mapHeight = value;
            }
        }

        LiteralControl div;            
       
        public BingMapsWebPart()
        {
            this.ExportMode = WebPartExportMode.All;
        }
        
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
                      
            createJSLinks();

            div = new LiteralControl();
            div.Text = createControlHost();
            this.Controls.Add(div);
        }

        private string createControlHost()
        {
            string controlHost = string.Format(@"<div id='silverlightControlHost' style='width: {1}px; height: {2}px;'>
                                                    <object data='data:application/x-silverlight-2,' type='application/x-silverlight-2' width='{1}px' height='{2}px'>
                                                        <param name='source' value='{0}'/>
                                                        <param name='onError' value='onSilverlightError' />
                                                        <param name='onLoad' value='onMapLoad' />
                                                        <param name='background' value='white' />
                                                        <param name='minRuntimeVersion' value='3.0.40818.0' />
                                                        <param name='autoUpgrade' value='true' />
                                                        <a href='http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40818.0' style='text-decoration:none'>
	                                                        <img src='http://go.microsoft.com/fwlink/?LinkId=161376' alt='Get Microsoft Silverlight' style='border-style:none'/>
                                                        </a>
                                                    </object>
                                                    <iframe id='_sl_historyFrame' style='visibility:hidden;height:0px;width:0px;border:0px'></iframe>
                                                </div>", SPContext.Current.Site.RootWeb.Url + "/_layouts/CodePlex/BingMapsWebPart/BingMapsWebPart.xap", mapWidth, mapHeight);
            return controlHost;
        }       

        protected override void Render(HtmlTextWriter writer)
        {
            base.Render(writer);
        }

        private void createJSLinks()
        {
            SPWeb web = SPContext.Current.Web;

            string js1 = web.Url + @"/_layouts/CodePlex/BingMapsWebPart/Silverlight.js";
            createJSLink(js1);

            LiteralControl lc2 = new LiteralControl();
            lc2.Text = "<script type=\"text/javascript\">" + Environment.NewLine + createSilverlightJs() + Environment.NewLine + "</script>" + Environment.NewLine;
            this.Page.Header.Controls.Add(lc2);

            LiteralControl lc3 = new LiteralControl();
            lc3.Text = "<script type=\"text/javascript\">" + Environment.NewLine + createMapInitJs() + Environment.NewLine + "</script>" + Environment.NewLine;
            this.Page.Header.Controls.Add(lc3);
        }
        
        private void createJSLink(string js)
        {
            LiteralControl lc = new LiteralControl();
            lc.Text = "<script type=\"text/javascript\" src=\"" + js + "\"></script>" + Environment.NewLine;
            
            if (this.Page.Header != null)
            {
                this.Page.Header.Controls.Add(lc);
            }
        }

        private string createMapInitJs()
        {
            string markerContentJs = getMarkerContentJs();
            string mapInitJs = getMapInitJs();

            string s = string.Empty;

            if (!string.IsNullOrEmpty(markerContentJs))
            {
                s = @"function onMapLoad(sender, args) 
                    {
                        var mapControl = sender.getHost(); " +
                        mapInitJs +
                        markerContentJs +
                    "}";
            }

            return s;
        }

        private string getMapInitJs()
        {
            string s = string.Format(@"var mapSettings = mapControl.content.services.createObject('MapSettings');       
            mapSettings.ZoomLevel = {0};
            mapSettings.Latitude = {1};
            mapSettings.Longitude = {2};
            mapSettings.AerialMode = '{3}';
            mapSettings.Labels = '{4}';
            mapSettings.Width = {5};
            mapSettings.Height = {6};
            mapControl.content.MainPage.InitMap(mapSettings); ", zoomLevel, latitude, longitude, aerialMode, labels, mapWidth, mapHeight) + Environment.NewLine;

            return s;
        }
        
        private string getMarkerContentJs()
        {
            string markerContentJs = string.Empty;

            SPWeb web = SPContext.Current.Web;

            try
            {
                foreach (SPListItem item in web.Lists[listName].Items)
                {
                    markerContentJs += string.Format("addMarker(mapControl, '{0}', {1}, {2}, {3});", item["Title"], item["Latitude"], item["Longitude"], 0) + Environment.NewLine;
                }
            }
            catch (ArgumentException)
            {
                if (string.IsNullOrEmpty(listName))
                    RegisterError("Bing Maps source list name is not set. Edit web part properties to set correct list name. ");
                else
                    RegisterError("Bing Maps source list name: " + listName + " is not found.");
            }

            return markerContentJs;
        }

        private static string createSilverlightJs()
        {
            string s = @"function onSilverlightError(sender, args) {
                            var appSource = '';
                            if (sender != null && sender != 0) {
                              appSource = sender.getHost().Source;
                            }
                            
                            var errorType = args.ErrorType;
                            var iErrorCode = args.ErrorCode;

                            if (errorType == 'ImageError' || errorType == 'MediaError') {
                              return;
                            }

                            var errMsg = 'Unhandled Error in Silverlight Application ' +  appSource + '\n' ;

                            errMsg += 'Code: '+ iErrorCode + '    \n';
                            errMsg += 'Category: ' + errorType + '       \n';
                            errMsg += 'Message: ' + args.ErrorMessage + '     \n';

                            if (errorType == 'ParserError') {
                                errMsg += 'File: ' + args.xamlFile + '     \n';
                                errMsg += 'Line: ' + args.lineNumber + '     \n';
                                errMsg += 'Position: ' + args.charPosition + '     \n';
                            }
                            else if (errorType == 'RuntimeError') {           
                                if (args.lineNumber != 0) {
                                    errMsg += 'Line: ' + args.lineNumber + '     \n';
                                    errMsg += 'Position: ' +  args.charPosition + '     \n';
                                }
                                errMsg += 'MethodName: ' + args.methodName + '     \n';
                            }

                            throw new Error(errMsg);
                        }

                        function addMarker(mapControl, name, lat, lon, type) 
                        {
                            var marker = mapControl.content.services.createObject('Marker');
                            marker.Name = name;
                            marker.Latitude = lat;
                            marker.Longitude = lon;
                            marker.MarkerType = type;

                            mapControl.content.MainPage.AddMarker(marker);
                        }";
               
            return s;
        }
            
        private string createVideoJs()
        {            
            SPWeb web = SPContext.Current.Web;

            string videoJs = string.Empty;

            try
            {
                if (web.Lists[listName].Items.Count == 0)
                    return string.Empty;

                videoJs = "'this._playlist=['+";

                int i = 1;

                foreach (SPListItem video in web.Lists[listName].Items)
                {
                    videoJs +=
                                "'{\"mediaSource\":\"" + video["ows_EncodedAbsUrl"] + "\",'+ " + 
                                "'\"placeholderSource\":\"\",'+ " + 
                                "'\"chapters\":'+" +
                                "'['+" +
		                        "']}'+";

                    if (i < web.Lists[listName].ItemCount)
                    {
                        videoJs += "',' +";
                    }

                    i++;
                }
            }
            catch
            {
                // libraryName was not found.
                videoJs = string.Empty;
            }

            videoJs += "'];'";

            //return videoJs;
            return videoJs;		           
        }
    }
}